/** 统一的异常处理 */
import axios, { AxiosError } from 'axios';
import type { App } from "vue";
import { APIException } from './exception';
import {ElMessage} from "element-plus";

type AllError = Error | APIException | AxiosError | null;

/** 保证同样的错误只提示一次，防止多个接口同时报网络异常，同时弹出多个提示框 */
const handleErrorMsg = (() => {
  let prevMsg = '';

  return (msg: string) => {
    if (msg && msg !== prevMsg) {
      ElMessage({
        duration: 3000,
        message: msg,
        type: "error",
        onClose: () => {
          prevMsg = "";
        },
      });
      prevMsg = msg;
    }
  };
})();

/* 当一个页面有多个错误的时候，可能会弹框多次，那能不能保证 */
/** 处理后台接口数据异常 */
const handleAPIError = (error: APIException) => {
  // 还可以处理权限异常 比如后端自定义code值
  const authErrMap: Record<number, string> = {
    10031: '登录失效，需要重新登录', // token 失效
    10032: '您太久没登录，请重新登录~', // token 过期
    10034: '该用户未注册，请联系管理员注册用户',
    10037: '账号已无效',
    10038: '账号未找到',
  };

  let errorMsg = error.message || '异常请重试';
  if (error.code in authErrMap) {
    errorMsg = authErrMap[error.code];
  }
  handleErrorMsg(errorMsg);
};

/** 处理axios异常，比如4xx/5xx错误  */
const handleCommonError = (error: AxiosError) => {
  const status = error.response?.status || -1;

  const handleErrorMsgMap: Record<number, () => string> = {
    400: () => '错误的请求参数',
    // token失效，重定向到登录页面
    401: () => {
      setTimeout(() => {
        window.dispatchEvent(new CustomEvent('SHOW_LOGIN'));
      }, 1000);

      return '登录已过期，请重新登录';
    },
    403: () => '拒绝访问',
    404: () => '请求错误,未找到该资源',
    408: () => '请求超时',
    500: () => '服务器端出错',
    502: () => '网络错误',
    503: () => '服务不可用',
    504: () => '网络超时',
  };

  const errMessage = handleErrorMsgMap[status]?.() || error.message || '异常请重试';

  handleErrorMsg(errMessage);
};

const commonErrorHandler = (error: AllError) => {
  if (axios.isAxiosError(error)) {
    handleCommonError(error);
  } else if (error instanceof APIException) {
    handleAPIError(error);
  } else if ((error as AxiosError).name === 'ChunkLoadError') {
    // 资源加载失败，认为是版本更新
    message.info({
      content: '网页已更新，3秒后自动刷新页面',
      onClose: () => window.location.reload(),
    });
  }
  // 其他异常暂不不处理
};

const runtimeErrorHandler = (error: ErrorEvent) => {
  commonErrorHandler(error.error);
};

const promiseRejectHandler = (error: PromiseRejectionEvent) => {
  commonErrorHandler(error.reason);
};

// 这个在入口文件注册即可
export const initErrorHandler = (app: App<Element>) => {
  // 先清除在绑定
  window.removeEventListener('error', runtimeErrorHandler);
  window.removeEventListener('unhandledrejection', promiseRejectHandler);
  window.addEventListener('error', runtimeErrorHandler);
  window.addEventListener('unhandledrejection', promiseRejectHandler);
  app.config.errorHandler = (err) => {
    commonErrorHandler(err)
  }
};
